package cn.itsource.ymcc.service.impl;

import cn.itsource.ymcc.constant.ErrorConstantCode;
import cn.itsource.ymcc.domain.*;
import cn.itsource.ymcc.dto.CourseDTO;
import cn.itsource.ymcc.dto.CourseDocumentDto;
import cn.itsource.ymcc.exception.GlobalException;
import cn.itsource.ymcc.feign.client.CourseSearchFeignClient;
import cn.itsource.ymcc.feignclient.MediaFileFeignClient;
import cn.itsource.ymcc.mapper.CourseMapper;
import cn.itsource.ymcc.result.JSONResult;
import cn.itsource.ymcc.service.*;
import cn.itsource.ymcc.util.AssertUtil;
import cn.itsource.ymcc.vo.CourseDetailVO;
import cn.itsource.ymcc.vo.CourseOrderDetailVo;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.rocketmq.client.producer.SendCallback;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author gwk
 * @since 2023-02-24
 */
@Service
@Slf4j
public class CourseServiceImpl extends ServiceImpl<CourseMapper, Course> implements ICourseService {

    @Autowired
    private ITeacherService teacherService;

    @Autowired
    private ICourseMarketService marketService;

    @Autowired
    private ICourseDetailService detailService;

    @Autowired
    private ICourseChapterService chapterService;

    @Autowired
    private ICourseResourceService resourceService;

    @Autowired
    private ICourseSummaryService summaryService;

    @Autowired
    private ICourseTypeService typeService;

    @Autowired
    public CourseSearchFeignClient courseFeign; // feign接口 -- 操作ES

    @Autowired
    public MediaFileFeignClient mediaFileFeign;

    /**
     * 1. 校验
     * 2. 判断课程已存在
     * 3. 保存到course， 课程状态，老师的名字查询。添加课程的员工, 封面
     * 4. 在保存 market 和 detail， 课程资源 resource
     * 5. 在课程分类 coursertye 课程数量+1
     * @param courseDTO
     */
    @Override
    @Transactional(propagation= Propagation.REQUIRED,readOnly = false)
    public void save(CourseDTO courseDTO) {
        // 1. 获取参数进行校验 --》 JS303
        Course course = courseDTO.getCourse();
        CourseDetail courseDetail = courseDTO.getCourseDetail();
        CourseMarket courseMarket = courseDTO.getCourseMarket();
        CourseResource courseResource = courseDTO.getCourseResource();
        List<Long> teacharIds = courseDTO.getTeacharIds();

        // 2. 不需要判断课程已存在的
        // 3. 根据teacherid.查询老师的名字，拼接成字符， 保存到course
        insertCouse(course, teacharIds);

        // 5. 在保存 market 和 detail
        courseMarket.setId(course.getId());
        courseDetail.setId(course.getId());
        courseResource.setCourseId(course.getId());

        resourceService.insert(courseResource);
        marketService.insert(courseMarket);
        detailService.insert(courseDetail);

        // 6. 在对应课程分类下新增课程数量
        typeService.addTotalCount(course.getCourseTypeId());

    }

    /**
     * 课程上架
     * @param courseId
     */
    @Override
    public void onLineCourse(Long courseId) {
        // 修改数据库中的状态
        Course course = selectById(courseId);
        AssertUtil.isNotNull(course, ErrorConstantCode.COURSE_ERROR_30010);
        AssertUtil.isEquals(Course.COURSE_OFFLINE,course.getStatus(),ErrorConstantCode.COURSE_ONLINE_ERROR_30030);
        course.setStatus(Course.COURSE_ONLINE);


        CourseDocumentDto documentDto = getCourseDocumentDto(courseId, course);

        // 通过Feign 调用 search-server 实现课程上架
        JSONResult jsonResult = courseFeign.courseOnline(documentDto);
        AssertUtil.isTrue(jsonResult.isSuccess(),ErrorConstantCode.COURSE_ONLINE_ERROR_30020);

        //ES 操作成功，本地数据库查进行修改
        updateById(course);// 修改

        // 发送课程信息到MQ
        sendCourseMessage(documentDto);

    }

    @Override
    public CourseDetailVO getDetail(Long courseId) {
        // 1.参数非空校验
        AssertUtil.isNotNull(courseId,ErrorConstantCode.PARAMETER_NOT_BE_NULL);
        // 2. 查询课程信息 course
        Course course = selectById(courseId);
        // 3. 判断课程要存在且已经上线
        AssertUtil.isNotNull(course,ErrorConstantCode.COURSE_ERROR_30010);
        AssertUtil.isTrue(course.getStatus().equals(Course.COURSE_ONLINE),ErrorConstantCode.COURSE_NOT_ONLINE_30060);

        // 4. 查询其他课程信息 detail  market  courseSummary
        CourseDetail detail = detailService.selectById(courseId);
        CourseMarket market = marketService.selectById(courseId);
        CourseSummary summary = summaryService.selectById(courseId);

        // course_teacher 通过中建表
        List<Teacher> teachers = teacherService.getTeachersByCourseId(courseId);

        // course_chapter -> media --> List<media>  medias = Openfeign。getMediaByCourseID(courseId)
        List<CourseChapter> courseChapters = chapterService.listByCourseId(courseId);
        // 不在循环中查询 media 信息，效率问题
        JSONResult jsonResult = mediaFileFeign.getMediaslistByCourseId(courseId);
        AssertUtil.isTrue(jsonResult.isSuccess(),ErrorConstantCode.COURSE_NOT_MEIDA_30070);
        // 转化 Feign调用的结果
        List<MediaFile> mediaFiles = JSON.parseArray(JSON.toJSONString(jsonResult.getData()),MediaFile.class);

        //Map<Long,MediaFile> mediaFileMap = mediaFiles.stream().collect(Collectors.toMap(MediaFile::getChapterId,mediaFile -> mediaFile));
        Map<Long, CourseChapter> chapterMap = courseChapters.stream().collect(Collectors.toMap(CourseChapter::getId, chapter -> chapter));

        // 遍历章节，添加media信息
        for (MediaFile mediaFile : mediaFiles) {
            Long chapterId = mediaFile.getChapterId();
            if (chapterId != null){
                CourseChapter courseChapter = chapterMap.get(chapterId);
                if(courseChapter!=null){
                    mediaFile.setFileUrl(""); // 先把视频的地址置空
                    courseChapter.getMediaFiles().add(mediaFile);
                }
            }
        }

        // 封装 vo对象 返回结果
        CourseDetailVO courseDetailVO = new CourseDetailVO();
        courseDetailVO.setCourse(course);
        courseDetailVO.setCourseDetail(detail);
        courseDetailVO.setCourseMarket(market);
        courseDetailVO.setTeachers(teachers);
        courseDetailVO.setCourseSummary(summary);
        courseDetailVO.setCourseChapters(courseChapters);

        return courseDetailVO;
    }

    @Autowired
    private ICourseUserLearnService courseUserLearnService;

    @Override
    public CourseUserLearn getCourseforuser(Long courseId, Long loginId) {
        Wrapper<CourseUserLearn> wrapper = new EntityWrapper<>();
        wrapper.eq("login_id",loginId).and().eq("course_id",courseId);
        return courseUserLearnService.selectOne(wrapper);
    }

    /**
     * 查询订单确实页面的课程信息
     * @param courseIds
     * @return
     */
    @Override
    public CourseOrderDetailVo getOrderDetail(String courseIds) {
        // 1. 前端传递的参数校验
        AssertUtil.isNotNull(courseIds,ErrorConstantCode.PARAMETER_NOT_BE_NULL);
        String[] split = courseIds.split(",");
        // 校验课程id
        List<Long> courseIdslist = null;
        try{
            courseIdslist = Arrays.stream(split).filter(id-> StringUtils.isNotBlank(id))
                    .map(id->Long.valueOf(id)).collect(Collectors.toList());
            AssertUtil.isTrue(courseIdslist.size()==split.length,ErrorConstantCode.PARAMETER_NOT_BE_NULL);
        }catch (Exception e){
            e.printStackTrace();
            throw  new GlobalException("参数校验异常！");
        }

        // 2. 查询课程信息
        CourseOrderDetailVo courseOrderDetailVo = new CourseOrderDetailVo();
        for (Long courseid : courseIdslist) {
            CourseDetailVO detail = getDetail(courseid);
            AssertUtil.isNotNull(detail,ErrorConstantCode.COURSE_ERROR_30010);
            // 课程未上架也不可以购买
            AssertUtil.isTrue(Course.COURSE_ONLINE.equals(detail.getCourse().getStatus()),ErrorConstantCode.COURSE_NOT_ONLINE_30060);
            courseOrderDetailVo.getCourseInfos().add(detail);
            // 计算总价
            courseOrderDetailVo.setTotalAmount(courseOrderDetailVo.getTotalAmount().add(detail.getCourseMarket().getPrice()));
        }
        return courseOrderDetailVo;
    }

    @Autowired
    private RocketMQTemplate template;

    private void sendCourseMessage(CourseDocumentDto documentDto) {
        documentDto.setIntro("");
        String jsonStr = JSON.toJSONString(documentDto);
        template.asyncSend("course-topic:online-tags", MessageBuilder.withPayload(jsonStr).build(), new SendCallback() {
            @Override
            public void onSuccess(SendResult sendResult) {
                log.info("课程上线消息，发送成功！！");
            }

            @Override
            public void onException(Throwable throwable) {
                throwable.printStackTrace();
                log.info("课程上线消息发送到MQ失败！！"+ jsonStr);
            }
        });
    }


    //  根据courseId查询课程信息，封装dto
    // course ,course_detail,market,summary,type
    private CourseDocumentDto getCourseDocumentDto(Long courseId, Course course) {
        CourseDetail courseDetail = detailService.selectById(courseId);
        CourseMarket courseMarket = marketService.selectById(courseId);
        CourseSummary courseSummary = summaryService.selectById(courseId);

        CourseType courseType = typeService.selectById(course.getCourseTypeId());

        // 封装到 CourseDocumentDto
        CourseDocumentDto documentDto = new CourseDocumentDto();

        if(courseSummary!=null){
            BeanUtils.copyProperties(courseSummary,documentDto);
        }
        if(courseType!=null){
            documentDto.setCourseTypeName(courseType.getName());
        }

        BeanUtils.copyProperties(course,documentDto);
        BeanUtils.copyProperties(courseDetail,documentDto);
        BeanUtils.copyProperties(courseMarket,documentDto);


        log.info(documentDto.toString());
        return documentDto;
    }


    private void insertCouse(Course course, List<Long> teacharIds) {
        List<Teacher> teachers = teacherService.selectBatchIds(teacharIds);
        if(teachers!=null && teachers.size()>0){
            StringBuffer sb = new StringBuffer();
            teachers.forEach(teacher -> {
                sb.append(teacher.getName()).append(",");

            });
            course.setTeacherNames(sb.substring(0,sb.length()-1));
        }

        // 设置 课程属性
        course.setStatus(0); // 未上架
        course.setLoginId(1L);
        course.setLoginUserName("亮亮");
        course.setChapterCount(0);

        // 4. 保存数据，先保存Course，获取course_id
        insert(course);
    }
}
